package reservation;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import serialisation.DataManager;
import data.Ville;
import errors.NegativeValueException;
import errors.StartStopException;

/**
 * Classe serveur : représente le coeur de l'application. Elle effectue toutes
 * les opérations relatives à la demande du client. C'est la seule classe qui
 * est en relation avec les fichiers de données
 * 
 * @author Alexandre Boursier and Mamadou Diallo and Cyril Gorrieri and Emmanuel Menage
 * @version 2012.01.23
 */

public class Serveur {

    /**
     * Singleton du serveur
     */
    private static Serveur instance;

    /**
     * Recupère le singleton du serveur
     * 
     * @return le serveur
     */
    public static Serveur getInstance() {
        if(instance == null) {
            instance = new Serveur();
            if(DataManager.load() == false) {
                throw new Error("Load Failed !!");
            }
        }
        return instance;
    }

    /**
     * Constructeur  privé pour le Singleton
     */
    private Serveur() {}

    /**
     * enregistre l'etat courant du serveur
     */
    public void save() {
        if (DataManager.store()) {
            System.out.println("Sauvegarde effecutée avec succés");
        } else {
            System.out.println("Erreur: La sauvegarde a échoué");
        }
        // TODO ajouter store autre serializer
    }

    /**
     * Traiter la demande de réservation d'un client simple et lui indiquer la
     * réponse
     * 
     * @param cli
     *            Le client demandeur
     * @param transport
     *            Le trajet cible
     * @return
     * 			true si la réservation a bien eu lieu, false sinon
     * @throws IOException
     */
    public boolean traiterDemandeReservation(Billet b)
            throws IOException {
        if (DataManager.store(b)) {
            System.out.println("Votre réservation est confirmée");
            return true;
        } else {
            System.out.println("Votre demande de réservation n'a pas pu aboutir");
            return false;
        }
    }
    
    /**
     * Demande au serveur s'il est possible de réserver un billet
     * @param b 
     * 			le billet qu'on souhaite réserver
     * @return true s'il ya possiblité de faire une reservation du billet, false sinon.
     */
    public boolean canReserve(Billet b) {
    	return DataManager.canReserve(b);
    }

    /**
     * Ajouter un transport
     * 
     * @param t
     *            Le transport cible
     * @return true si le transport est ajouté à la base de données, false sinon
     * @throws NumberFormatException
     * @throws NullPointerException
     * @throws IOException
     * @throws NegativeValueException
     * @throws StartStopException
     */
    public boolean add(Transport t) throws NumberFormatException,
    NullPointerException, IOException, NegativeValueException,
    StartStopException {
        if (DataManager.store(t)) {
            System.out.println("Transport ajouté avec succès.");
            System.out.println(t);
            return true;
        } else {
            System.out
            .println("Erreur lors de l'ajout, la demande n'a pue aboutir");
            return false;
        }
    }

    /**
     * Ajouter un trajet
     * 
     * @param t
     *            Le trajet cible
     * @return true si le transport est ajouté à la base de données, false sinon
     * @throws NumberFormatException
     * @throws NullPointerException
     * @throws IOException
     * @throws NegativeValueException
     * @throws StartStopException
     */
    public boolean add(Trajet t) throws NumberFormatException,
    NullPointerException, IOException, NegativeValueException,
    StartStopException {
        if (DataManager.store(t)) {
            System.out.println("Trajet ajouté avec succès.");
            System.out.println(t);
            return true;
        } else {
            System.out
            .println("Erreur lors de l'ajout, la demande n'a pu aboutir");
            return false;
        }
    }

    /**
     * Supprimer un transport
     * 
     * @param t
     *            Le transport cible
     * @return true si le transport est modifié, false sinon
     * @throws NumberFormatException
     * @throws NullPointerException
     * @throws IOException
     * @throws NegativeValueException
     * @throws StartStopException
     */
    public boolean delete(Transport t) throws NumberFormatException,
    NullPointerException, IOException, NegativeValueException,
    StartStopException {
        if (DataManager.delete(t)) {
            System.out.println("Transport supprimé avec succès.");
            return true;
        } else {
            System.out
            .println("Erreur lors de la suppression, la demande n'a pue aboutir");
            return false;
        }
    }

    /**
     * Supprimer un trajet
     * 
     * @param t
     *            Le trajet cible
     * @return true si le trajet est modifié, false sinon
     * @throws NumberFormatException
     * @throws NullPointerException
     * @throws IOException
     * @throws NegativeValueException
     * @throws StartStopException
     */
    public boolean delete(Trajet t) throws NumberFormatException,
    NullPointerException, IOException, NegativeValueException,
    StartStopException {
        if (DataManager.delete(t)) {
            System.out.println("Trajet supprimé avec succès.");
            return true;
        } else {
            System.out
            .println("Erreur lors de la suppression, la demande n'a pue aboutir");
            return false;
        }
    }
    
    public boolean delete(Billet b) {
    	if (DataManager.delete(b)) {
            System.out.println("Billet supprimé avec succès.");
            return true;
        } else {
            System.out.println("Erreur lors de la suppression, la demande n'a pue aboutir ");
            return false;
        }
    }

    /**
     * Modifier un transport
     * 
     * @param t
     *            Le transport cible
     * @return true si le transport est modifié, false sinon
     * @throws NumberFormatException
     * @throws NullPointerException
     * @throws IOException
     * @throws NegativeValueException
     * @throws StartStopException
     */
    public boolean alter(Transport t) throws NumberFormatException,
    NullPointerException, IOException, NegativeValueException,
    StartStopException {
        if (DataManager.alter(t)) {
            System.out.println("Transport modifié avec succès.");
            System.out.println(t);
            return true;
        } else {
            System.out
            .println("Erreur lors de la modification, la demande n'a pue aboutir");
            return false;
        }
    }

    /**
     * Modifier un trajet
     * 
     * @param t
     *            Le trajet cible
     * @return true si le trajet est modifié, false sinon
     * @throws NumberFormatException
     * @throws NullPointerException
     * @throws IOException
     * @throws NegativeValueException
     * @throws StartStopException
     */
    public boolean alter(Trajet t) throws NumberFormatException,
    NullPointerException, IOException, NegativeValueException,
    StartStopException {
        if (DataManager.alter(t)) {
            System.out.println("Trajet modifié avec succès.");
            System.out.println(t);
            return true;
        } else {
            System.out
            .println("Erreur lors de la modification, la demande n'a pue aboutir");
            return false;
        }
    }

    /**
     * récupère la liste de trajets dans une chaine de caractère.
     * @param trajets
     * 				la liste de trajets
     * @return une chaine de caractère formatée qui contient la liste de trajets.
     */
    public String afficherTrajets(List<Trajet> trajets) {
        StringBuilder sb = new StringBuilder();
        for (Trajet t : trajets) {
            sb.append(t.toString());
        }
        return sb.toString();
    }

    /**
     * récupère la liste de transports dans une chaine de caractère.
     * @param transports
     * @return une chaine de caractère formatée qui contient la liste de transports.
     */
    public String afficherTransports(List<Transport> transports) {
        StringBuilder sb = new StringBuilder();
        for (Transport t : transports) {
            sb.append(t.toString());
        }
        return sb.toString();
    }

    /**
     * Affiche la liste des trajets
     */
    public void listeTrajets() {
        System.out.println(DataManager.listeTrajets());
    }

    /**
     * Affiche la liste des transports
     */
    public void listeTransports() {
        System.out.println(DataManager.listeTransports());
    }

    /**
     * Obtenir un transport en fonction de son identifiant
     * 
     * @param id
     *            L'identifiant du transport cible
     * @return
     */
    public Transport obtenirTransport(int id) {
        return DataManager.getTransportById(id);
    }

    /**
     * Obtenir un trajet en fonction de son identifiant
     * 
     * @param id
     *            L'identifiant du trajet cible
     * @return Le trajet si il existe sinon null
     */
    public Trajet obtenirTrajet(int id) {
        return DataManager.getTrajetById(id);
    }

    /**
     * Obtenir les trajets dont le client cible fait partie
     * 
     * @param c
     *            Le client cible
     */
    public void obtenirTrajets(Client c) {
        System.out.println(afficherTrajets(DataManager
                .getTrajetsByClient(c)));
    }

    /**
     * Obtenir les trajets dont le transport cible fait partie
     * 
     * @param t
     *            Le transport cible
     */
    public void obtenirTrajets(Transport t) {
        System.out.println(afficherTrajets(DataManager
                .getTrajetsByTransport(t)));
    }

    /**
     * Obtenir les trajets pour une date donnée
     * 
     * @param d
     *            La date cible
     */
    public void obtenirTrajets(Date d) {
        System.out
        .println(afficherTrajets(DataManager.getTrajetsByDate(d)));
    }

    /**
     * Obtenir les trajets pour une ville de départ donnée
     * 
     * @param v
     *            La ville cible
     */
    public void obtenirTrajets(Ville v) {
        System.out
        .println(afficherTrajets(DataManager.getTrajetsByVille(v)));
    }

    /**
     * Obtenir les transports partant à une date donnée
     * 
     * @param d
     *            La date cible
     */
    public void obtenirTransports(Date d) {
        System.out.println(afficherTransports(DataManager
                .getTransportsByDate(d)));
    }

    /**
     * Obtenir les transports partant à une date donnée
     * 
     * @param V
     *            La ville cible
     */
    public void obtenirTransports(Ville v) {
        System.out.println(afficherTransports(DataManager
                .getTransportsByVille(v)));
    }

    /**
     * Convertir en date
     * 
     * @param s
     *            La chaîne de caractères cible
     * @throws ParseException
     */
    public Date toDate(String s) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy à HH:mm");
        return sdf.parse(s);
    }
    
    /**
	 * Obtenir un client à travers son login
	 * 
	 * @param login
	 *            Le login recherché
	 * @return le client recherché.
	 */
    public Client getClientByLogin(String login) {
    	return DataManager.getClientByLogin(login);
    }
    
    /**
	 * récupère la liste des billets réservés par le client passé en paramètre
	 * @param c
	 * 			le client
	 * @return la liste des billets réservés par le client
	 */
    public List<Billet> obtenirBillets(Client c) {
    	return DataManager.obtenirBillets(c);
    }
}
